#include<iostream>

//多线程必须包含的头文件
#include<thread>
using namespace std;

//子线程1
void myThread() {
	for (int i = 0; i < 10;i++) {
		cout << "My thread" << endl;
	}
}

//子线程2
void myThread2() {
	for (int i = 0; i < 10; i++) {
		cout << "2" << endl;
	}
}

//子线程3
void myThread3() {
	for (int i = 0; i < 10;i++) {
		cout << "3" << endl;
	}
}

//创建类可调用对象，内部有仿函数的类变为可调用对象
//子线程4
class TA {
public:

	//问题：
	//如果用引用传入，并且子线程调用了detach（）方法
	//会导致子线程结束后，局部变量被销毁，子线程无法显示正确的内容
	//解决：
	//1、定义普通变量即可，可以普通变量相对于复制了一份给类对象
	//2、调用join方法而不是detach方法
	int& i;
	TA(int& p) :i(p) {};
	void operator()() {
		cout << "类线程，子线程4";
	}
	//验证复制了一个TA对象
	//自己重写拷贝构造
	TA(const TA &ta):i(ta.i) {
		cout << "TA的拷贝构造被调用" << endl;
	}
	//重写析构
	~TA() {
		cout << "ta的析构函数" << endl;
	}
};
int main(int argc, char* argv[] ) {
	
	//通过thread关键字新建进程对象（参数是我们需要执行的函数名称）
	//开始线程执行
	thread mythread(myThread);
	thread mythread2(myThread2);
	thread mythread3(myThread3);
	//其他创建线程的方法，创建类线程
	//不能传入临时变量，要先实例化一个对象
	//对于类对象，他也在主线程内部，并调用了detach，会因为主线程的结束被销毁
	//但是可以正常执行，这个对象实际上是被复制到线程中去（复制了一个对象）
	//所以主进程被销毁后，这个对象方法仍然可以调用
	//所以只要调用detach的类中没有指针/引用等，就可以正常运行
	int p = 10;
	TA ta(p);
	thread mythread4(ta);


	//lambda表达式创建线程
	auto mylambda = [] {
		cout << "lambda线程创建" << endl;
	};





	//我们的主线程执行语句
	for (int i = 0; i < 10; i++) {
		cout << "Hello world" << endl;
	}




	//join方法可以把线程对象加入的主线程的运行中去，并阻塞主线程，等待子线程执行完
    //完毕后同时结束,如果没有最后没有join调用，则会报错，并会由于主线程的退出，子线程无法
	//自己的任务，甚至文件损坏
	mythread.join();
	mythread2.join();

	//detach：分离，子线程和主线程分离，不再等待同时退出
	//分离后，子线程会驻留再后台运行，相对于被cpp接管，当子线程运行结束后，有运行时库
	//负责资源清理（此时子线程被称为守护线程）
	//detach会使主线程失去我们的控制
	//也会因为主线程的退出终端执行
	//之后不能再用join方法了
	mythread3.detach();
	//mythread3.join();不可以
	mythread4.detach();





	//方法joinable（），判断是否可以join返回值为true或false
	if (mythread3.joinable()) {
		cout << "线程3可以join";
	}
	else {
		cout << "线程3不可以join";
	}


	//主线程退出后，其他线程被强制结束
	//如果类主线程运行完毕会有两个类对象的析构，一个为源对象，一个是复制的对象
	return 0;
}